#pragma once
#include "DWorld.h"
#include "DVector3.h"
#include "DBody.h"
#include "DOde.h"

#define VALUE_PROP_WORLD(Type,Name)\
	Type DWorld::Name::get(){return dWorldGet##Name(_This);}\
	void DWorld::Name::set(Type value){dWorldSet##Name(_This,value);}

namespace Skill
{
	namespace Ode
	{		
		void DWorld::CollectManagedMemory()
		{
			_Gravity = nullptr;
			if(_Bodies)
				for each (DBody^ b in _Bodies->Values)
				{
					DRegisteredObjects::Remove(b);
					b->_Free = false;
					b->_World = nullptr;
				}
				_Bodies->Clear();
				_Bodies = nullptr;
		}
		void DWorld::AddBody(DBody^ b)
		{
			GeomKey k = DRegisteredObjects::GetKey(b->UnmanagedPointer);
			if(!_Bodies->ContainsKey(k))
				_Bodies->Add(k,b);
		}
		void DWorld::RemoveBody(DBody^ b)
		{
			GeomKey k = DRegisteredObjects::GetKey(b->UnmanagedPointer);			
			_Bodies->Remove(k);
		}

		DWorld::!DWorld()
		{				
			if(_Free && _This && DOde::IsInitialized)
			{					
				dWorldDestroy(_This);
			}
			_Free = false;
			_This = nullptr;
		}

		DVector3^ DWorld::Gravity::get()
		{
			if(!_Gravity)
				_Gravity = gcnew DVector3();
			dWorldGetGravity(_This,_Gravity->_This);
			return _Gravity;
		}
		void DWorld::Gravity::set(DVector3^ value)
		{
			dWorldSetGravity(_This,value->_This[0],value->_This[1],value->_This[2]);
		}

		dReal DWorld::ERP::get(){return dWorldGetERP(_This);}
		void DWorld::ERP::set(dReal value){dWorldSetERP(_This,value);}

		VALUE_PROP_WORLD(dReal,CFM);
		void DWorld::Step(dReal stepsize)
		{
			dWorldStep(_This,stepsize);
		}
		void DWorld::ImpulseToForce(dReal stepsize,dReal ix, dReal iy, dReal iz, DVector3^ Force)
		{
			dWorldImpulseToForce(_This,stepsize,ix, iy, iz, Force->_This);
		}
		void DWorld::QuickStep(dReal stepsize)
		{
			dWorldQuickStep(_This, stepsize);
		}
		VALUE_PROP_WORLD(int,QuickStepNumIterations);
		VALUE_PROP_WORLD(dReal,QuickStepW);

		dReal DWorld::ContactMaxCorrectingVelocity::get(){return dWorldGetContactMaxCorrectingVel(_This);}
		void DWorld::ContactMaxCorrectingVelocity::set(dReal value){dWorldSetContactMaxCorrectingVel(_This,value);}

		VALUE_PROP_WORLD(dReal,ContactSurfaceLayer);
		void DWorld::StepFast1(dReal stepsize, int maxiterations)
		{
			dWorldStepFast1(_This,stepsize, maxiterations);			
		}
		VALUE_PROP_WORLD(int,AutoEnableDepthSF1);
		VALUE_PROP_WORLD(dReal,AutoDisableLinearThreshold);
		VALUE_PROP_WORLD(dReal,AutoDisableAngularThreshold);
		//VALUE_PROP_WORLD(dReal,AutoDisableLinearAverageThreshold);
		//VALUE_PROP_WORLD(dReal,AutoDisableAngularAverageThreshold);
		VALUE_PROP_WORLD(int,AutoDisableAverageSamplesCount);
		VALUE_PROP_WORLD(int,AutoDisableSteps);
		VALUE_PROP_WORLD(dReal,AutoDisableTime);

		bool DWorld::AutoDisableFlag::get(){return dWorldGetAutoDisableFlag(_This) == 1;}
		void DWorld::AutoDisableFlag::set(bool value){dWorldSetAutoDisableFlag(_This,value? 1 : 0);}

		VALUE_PROP_WORLD(dReal,LinearDampingThreshold);
		VALUE_PROP_WORLD(dReal,AngularDampingThreshold);
		VALUE_PROP_WORLD(dReal,LinearDamping);
		VALUE_PROP_WORLD(dReal,AngularDamping);
		void DWorld::SetDamping(dReal linear_scale,dReal angular_scale)
		{
			dWorldSetDamping(_This,linear_scale,angular_scale);
		}
		VALUE_PROP_WORLD(dReal,MaxAngularSpeed);

	}
}